package drds.data_propagate.driver.packets.server;

import drds.data_propagate.driver.packets.AbstractPacket;
import drds.data_propagate.driver.packets.Capability;
import drds.data_propagate.driver.packets.HeaderPacket;
import drds.data_propagate.driver.utils.ByteHelper;
import drds.data_propagate.driver.utils.MSC;
import lombok.Getter;
import lombok.Setter;

import java.io.IOException;

/**
 * MySQL Handshake Initialization Packet.<br>
 */
public class HandshakeInitializationPacket extends AbstractPacket {
    @Setter
    @Getter
    public byte protocolVersion = MSC.DEFAULT_PROTOCOL_VERSION;
    @Setter
    @Getter
    public String serverVersion;
    @Setter
    @Getter
    public long threadId;
    @Setter
    @Getter
    public byte[] seed;
    @Setter
    @Getter
    public int serverCapabilities;
    @Setter
    @Getter
    public byte serverCharsetNumber;
    @Setter
    @Getter
    public int serverStatus;
    @Setter
    @Getter
    public byte[] restOfScrambleBuff;
    @Setter
    @Getter
    public byte[] authPluginName;

    public HandshakeInitializationPacket() {
    }

    public HandshakeInitializationPacket(HeaderPacket header) {
        super(header);
    }

    /**
     * <pre>
     * Bytes                        Name
     *  -----                        ----
     *  1                            protocol_version
     *  n (Null-Terminated String)   server_version
     *  4                            thread_id
     *  8                            scramble_buff
     *  1                            (filler) always 0x00
     *  2                            server_capabilities
     *  1                            server_language
     *  2                            server_status
     *  13                           (filler) always 0x00 ...
     *  13                           rest of scramble_buff (4.1)
     * </pre>
     */
    public void decode(byte[] bytes) {
        int index = 0;
        // 1. read protocol_version
        protocolVersion = bytes[index];
        index++;
        // 2. read server_version
        byte[] serverVersionBytes = ByteHelper.readNullTerminatedBytes(bytes, index);
        serverVersion = new String(serverVersionBytes);
        index += (serverVersionBytes.length + 1);
        // 3. read thread_id
        threadId = ByteHelper.readUnsignedIntLittleEndian(bytes, index);
        index += 4;
        // 4. read scramble_buff
        seed = ByteHelper.readFixedLengthBytes(bytes, index, 8);
        index += 8;
        index += 1; // 1 byte (filler) always 0x00
        // 5. read server_capabilities
        this.serverCapabilities = ByteHelper.readUnsignedShortLittleEndian(bytes, index);
        index += 2;
        if (bytes.length > index) {
            // 6. read server_language
            this.serverCharsetNumber = bytes[index];
            index++;
            // 7. read server_status
            this.serverStatus = ByteHelper.readUnsignedShortLittleEndian(bytes, index);
            index += 2;
            // 8. bypass filtered bytes
            int capabilityFlags2 = ByteHelper.readUnsignedShortLittleEndian(bytes, index);
            index += 2;
            int capabilities = (capabilityFlags2 << 16) | this.serverCapabilities;
            // int authPluginDataLen = -1;
            // if ((capabilities & Capability.CLIENT_PLUGIN_AUTH) != 0) {
            // authPluginDataLen = data[binlog_event_position_manager];
            // }
            index += 1;
            index += 10;
            // 9. read rest of scramble_buff
            if ((capabilities & Capability.CLIENT_SECURE_CONNECTION) != 0) {
                // int len = Math.max(13, authPluginDataLen - 8);
                // this.authPluginDataPart2 =
                // buffer.readFixedLengthString(len);// scramble2

                // Packet规定最后13个byte是剩下的scrumble,
                // 但实际上最后一个字节是0, 不应该包含在scrumble中.
                this.restOfScrambleBuff = ByteHelper.readFixedLengthBytes(bytes, index, 12);
            }

            index += 12 + 1;
            if ((capabilities & Capability.CLIENT_PLUGIN_AUTH) != 0) {
                this.authPluginName = ByteHelper.readNullTerminatedBytes(bytes, index);
            }
            // end read
        }
    }

    /**
     * Bypass implementing it, 'cause nowhere to use it.
     */
    public byte[] encode() throws IOException {
        return null;
    }

}
